﻿package org.sl.flvplayer.data {
	import org.sl.flvplayer.main.FLVPlayerApplication
	import org.sl.flvplayer.controls.PlayerLogic;
	import org.sl.flvplayer.flyweights.FWIcon;
	import org.sl.flvplayer.flyweights.FWPlayerCommand;
	import org.sl.flvplayer.flyweights.FWPreviewImage;
	import org.sl.flvplayer.helper.MathHelper;

	import flash.events.AsyncErrorEvent;
	import flash.events.NetStatusEvent;
	import flash.events.SecurityErrorEvent;
	import flash.media.SoundTransform;
	import flash.media.Video;
	import flash.net.NetConnection;
	import flash.net.NetStream;

	/**
	 * Every instance of the VideoItem class enables the playback of the current video and provides all the necessary data to controll it.</br>
	 * In addition information regarding opitional parameters like a watermark or an icon ect. is also provided.  
	 * 
	 * @package org.sl.flvplayer.data
	 * @author Dan
	 * @version 
	 * @see org.sl.flvplayer.data.Playlist
	 * @see org.sl.flvplayer.view.PlayerScreen
	 * @see org.sl.flvplayer.view.PlayerDisplay
	 */ 
	public class VideoItem {

		/**
		 * path to the video
		 */
		public var videoSource : String;

		/**
		 * previewimage generated from the current video or external source
		 */
		public var videoPreviewimage : FWPreviewImage;

		/**
		 * link adress to the specified html site
		 */
		public var link : String;

		/**
		 * icon of the link
		 */
		public var linkIcon : FWIcon;

		/**
		 * icon of the watermark
		 */
		public var watermarkIcon : FWIcon;

		/**
		 * netConnection
		 */
		public var main_nc : NetConnection;

		/**
		 * netstream
		 */
		public var ns : NetStream;

		/**
		 * video
		 */
		public var video : Video;

		/**
		 * indicates whether the video is started or not, default is false
		 */
		public var isStarted : Boolean = false;

		/**
		 * indicates whether the video is currently playing or not, default is false
		 */
		public var isPlaying : Boolean = false;

		/**
		 * states whether a linkicon is available or not, default is false
		 */
		public var iconAvailable : Boolean = false;

		/**
		 * states whether a watermarkIcon is available or not, default is false
		 */
		public var watermarkAvailable : Boolean = false;

		/**
		 * indicates if trackingdata will be send or not, default is false
		 */
		public var googleTrack : Boolean = false;

		/**
		 * backgroundcolor, default is 0x333333
		 */
		public var background : Number = 0x333333;

		/**
		 * duration of the video
		 */
		public var videoDuration : Number;

		/**
		 * contains corresponding timestamps of the keyframes
		 */
		public var keyFrameTimes : Array;

		/**
		 * contains corresponding fileposition of the keyframes
		 */
		public var keyFrameFilePositions : Array;
		
		/**
		 * path to the server if rtmp streaming is used
		 */
		public var server : String = null;
		
		/**
		 * path to the server if rtmp streaming is used
		 */
		private var firstPlay : Boolean = true;
		
		/**
		 * VideoItem constructor establishes a new netConnection, sets the videoSource and the videoPreviewimage and all the other optional parameters in the childnodes of the p_video xml node.
		 * 
		 * @param p_video is an xml object containing the filepath and optional information regarding the current video
		 */
		public function VideoItem(p_video : XML) {		
			videoSource = p_video.@src;						
			videoPreviewimage = new FWPreviewImage(videoSource, p_video.@previewimage);		
			// setting up a netconnection and other event handlers assigned to the netconnection client property
			main_nc = new NetConnection();			
			main_nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
			main_nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
			main_nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
			// server can be set for rtmp streaming
			main_nc.connect(server);
			
			for each (var node : XML in p_video.children()) {
				switch(node.name().toString()) {
					case "link":
						if(node.@icon != undefined && node.@icon != "") {
							link = node.@href;
							iconAvailable = true;
							linkIcon = new FWIcon(node.@icon, node.@iconpos);
						}				
						break;
				
					case "watermark":
						if(node.@icon != undefined && node.@icon != "") {
							watermarkAvailable = true;
							watermarkIcon = new FWIcon(node.@icon, node.@iconpos);	
						}			
						break;
	
					case "google":
						googleTrack = String(node.@track).toLowerCase() == "true"; 
						break;
					
					case "background":
						background = MathHelper.htmlHexToNumber(node.@color);
						break;
				}
			}
		}

		/**
		 * Handles netConnection and netStream status events.
		 *   
		 * @param netStatus object containing netStatus specific information
		 */
		private function onNetStatus(netStatus : Object) : void {	
			switch (netStatus.info.code) {
				case "NetConnection.Connect.Success":	
					// play stream if connection successful
					connectStream();				
					break;
				case "NetStream.Play.StreamNotFound":
					// error if stream file not found in
					// location specified
					FLVPlayerApplication.SOS_TRACER.alert("Stream not found: " + videoSource);
					break;	
				case "NetStream.Play.Stop":
					// do if video is stopped
					if(Config.getInstance().autoNext) { 
						Playlist.getInstance().playNext();
					} else {
						PlayerLogic.getInstance().command(new FWPlayerCommand(FWPlayerCommand.STOP, this)); 		
					}
					break;				
			}
		}

		/**
		 * Establishes a new netconnection, adds the necessary listeners and ensures that the metadata is available.
		 */
		private function connectStream() : void {
			ns = new NetStream(main_nc);
			// other event handlers assigned 
			// to the netstream client property
			ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
			ns.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
			ns.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
			var custom_obj : Object = new Object();
			custom_obj.onMetaData = onMetaDataHandler;	
			custom_obj.onCuePoint = onCuePointHandler;
			custom_obj.onPlayStatus = playStatus;
			// netstream object
			ns.client = custom_obj;				
			// attach netstream to the video object
			video = new Video();
			video.width = PlayerLogic.getInstance().playerScreen.stage.stageWidth;
			video.height = PlayerLogic.getInstance().playerScreen.stage.stageHeight - PlayerLogic.getInstance().margin;
			video.attachNetStream(ns);
			ns.bufferTime = 6;
		}

		/**
		 * @param p_soundTransform
		 */
		public function set sound(p_soundTransform : SoundTransform) : void {
			//enables sound manipulation
			ns.soundTransform = p_soundTransform;
		}

		/** 
		 * @return
		 */
		public function get sound() : SoundTransform {
			return ns.soundTransform;
		}

		/**
		 * Handles the metadata when they are available and when pseudostreaming is enabled assigns the keyframes to the associative array represented by keyFrameTimes and keyFrameFilePositions.
		 * 
		 * @param metaInfoObj contains the metadata of the video
		 */
		private function onMetaDataHandler(metaInfoObj : Object) : void {
			// FLVPlayerApplication.SOS_TRACER.alert("filepositions " + metaInfoObj.keyframes.filepositions+ "times " + metaInfoObj.keyframes.times); 									
			videoDuration = metaInfoObj.duration;
			// checks for streamingMode	and keyframes			
			if(Config.getInstance().streamingMode && metaInfoObj.keyframes) {
				keyFrameTimes = metaInfoObj.keyframes.times;
				keyFrameFilePositions = metaInfoObj.keyframes.filepositions;
			}
			if (metaInfoObj.width) video.width = metaInfoObj.width;
			if (metaInfoObj.height) video.height = metaInfoObj.height;
			PlayerLogic.getInstance().scaleFunction();
			//FLVPlayerApplication.SOS_TRACER.config("videoMetadata", metaInfoObj);
		}	

		/**
		 * CuePoint handler.
		 * 
		 * @param cueInfoObj contains <code>cuePoint</code> Information
		 */
		private function onCuePointHandler(cueInfoObj : Object) : void {
			//FLVPlayerApplication.SOS_TRACER.alert("cuepoint: time= " + cueInfoObj.time + " name= " + cueInfoObj.name + " type= " + cueInfoObj.type + " parameters " + cueInfoObj.parameters);
		}
		
		
		/**
		 * Play/continue netstream.
		 */
		public function playStream() : void {
			//FLVPlayerApplication.SOS_TRACER.config("playStream: firstPlay = " + firstPlay);
			if (firstPlay) {
				ns.play(videoSource);
				ns.pause();
				firstPlay = false;
				PlayerLogic.getInstance().playerScreen.playerDisplay.resizePreviewimage();
			}
			ns.resume();
		}

		
		/**
		 * PlayStatus handler.
		 * 
		 * @param playInfoObj contains information about the <code>playStatus</code>
		 */
		private function playStatus(playInfoObj : Object) : void { 										
			switch (playInfoObj.info.code) {
				case "NetStream.Play.Switch":
					// FLVPlayerAplication.SOS_TRACER.alert("?");
					break;
				 
				case "NetStream.Play.Complete":
					// FLVPlayerAplication.SOS_TRACER.alert("?");
					break;
			}
		}

		/**
		 * Handles security errors.
		 * 
		 * @param p_event
		 */
		private function securityErrorHandler(p_event : SecurityErrorEvent) : void {
			// FLVPlayerAplication.SOS_TRACER.alert("securityErrorHandler: " + p_event);
		}

		/**
		 * Handles asyncerrors.
		 * 
		 * @param p_event
		 */
		private function asyncErrorHandler(p_event : AsyncErrorEvent) : void {
			// FLVPlayerAplication.SOS_TRACER.alert("asyncErrorHandler: " + p_event.text);
		}

		/**
		 * States whether the previewimage is allready loaded or not.
		 * 
		 * @return returns <code>true</code> when the previewimage is loaded or <code>false</code> if it isn`t
		 */
		public function isLoaded() : Boolean {
			return videoPreviewimage.isLoaded();
		}
	}
}

